"""商家信用评分模块.

本模块实现商家信用评分系统的核心功能:

1. 评分维度
   - 交易维度(25%): 交易额、频率、稳定性
   - 服务维度(20%): 响应速度、退款处理、争议解决
   - 商品维度(20%): 商品质量、描述准确性、库存管理
   - 活跃维度(15%): 店铺年龄、登录频率、活动参与
   - 合规维度(20%): 资质完备性、违规记录、投诉率

2. 评分等级
   - S+ (钻石级): 900-1000分
   - S  (金牌级): 800-899分
   - A+ (银牌级): 700-799分
   - A  (铜牌级): 600-699分
   - B+ (信用级): 500-599分
   - B  (观察级): 400-499分
   - C+ (受限级): 300-399分
   - C  (高危级): 200-299分
   - D  (禁止级): 0-199分

3. 评分权益
   - 搜索展示优先级
   - 平台服务费率
   - 商家标识
   - 活动参与权限
"""

from datetime import datetime
from typing import Dict, List, Optional, Tuple

import numpy as np

from ..data.data_loader import DataLoader
from ..features.feature_engineering import FeatureEngineer
from ..utils.logger import logger
from .config import (MERCHANT_PRIVILEGES, MERCHANT_WEIGHTS, SCORE_PARAMS,
                    SCORE_RANGES)


class CreditScorer:
    """商家信用评分类."""
    
    def __init__(self):
        """初始化商家评分器."""
        self.data_loader = DataLoader()
        self.feature_engineer = FeatureEngineer()
    
    def calculate_merchant_score(
        self,
        merchant_id: str
    ) -> Tuple[float, Dict[str, float], str, List[str]]:
        """计算商家信用评分.
        
        Args:
            merchant_id: 商家ID
            
        Returns:
            Tuple[float, Dict[str, float], str, List[str]]:
                总分, 维度得分, 信用等级, 权益列表
                
        评分流程:
        1. 加载商家数据
        2. 处理特征数据
        3. 计算维度得分
        4. 确定信用等级
        5. 获取对应权益
        """
        try:
            # 加载商家数据
            raw_features = self.data_loader.load_merchant_data(merchant_id)
            
            if not raw_features:
                logger.warning(f"未找到商家数据: {merchant_id}")
                return SCORE_PARAMS["base_score"], {}, "B", MERCHANT_PRIVILEGES["B"]
            
            # 处理特征
            processed_features = self.feature_engineer.process_merchant_features(
                raw_features
            )
            
            # 标准化特征
            normalized_features = self.feature_engineer.normalize_features(
                processed_features
            )
            
            # 计算加权得分
            overall_score, dimension_scores = self.feature_engineer.calculate_weighted_score(
                normalized_features,
                MERCHANT_WEIGHTS
            )
            
            # 转换为最终分数
            final_score = self._scale_score(overall_score)
            
            # 确定信用等级和权益
            credit_level = self._determine_credit_level(final_score)
            privileges = self._get_merchant_privileges(credit_level)
            
            # 保存评分
            self._save_merchant_score(
                merchant_id=merchant_id,
                score=final_score,
                dimension_scores=dimension_scores
            )
            
            return final_score, dimension_scores, credit_level, privileges
            
        except Exception as e:
            logger.error(f"计算商家评分时发生错误: {e}")
            raise
    
    def get_merchant_score_history(
        self,
        merchant_id: str,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None
    ) -> List[Dict]:
        """获取商家历史评分记录.
        
        Args:
            merchant_id: 商家ID
            start_date: 开始日期
            end_date: 结束日期
            
        Returns:
            List[Dict]: 历史评分记录列表
        """
        try:
            query = """
            SELECT
                score,           -- 总分
                score_details,   -- 维度得分
                created_at       -- 评分时间
            FROM credit_scores
            WHERE
                entity_id = :merchant_id
                AND entity_type = 'merchant'
            """
            
            params = {"merchant_id": merchant_id}
            
            if start_date:
                query += " AND created_at >= :start_date"
                params["start_date"] = start_date
                
            if end_date:
                query += " AND created_at <= :end_date"
                params["end_date"] = end_date
                
            query += " ORDER BY created_at DESC"
            
            with self.data_loader.get_engine().connect() as conn:
                result = conn.execute(query, params).fetchall()
            
            return [
                {
                    "score": row[0],
                    "details": row[1],
                    "timestamp": row[2].isoformat()
                }
                for row in result
            ]
            
        except Exception as e:
            logger.error(f"获取商家历史评分时发生错误: {e}")
            raise
    
    def update_merchant_scores(self, batch_size: int = 1000) -> int:
        """批量更新商家评分.
        
        Args:
            batch_size: 批处理大小
            
        Returns:
            int: 处理的商家数量
        """
        try:
            # 获取所有商家ID
            query = "SELECT DISTINCT merchant_id FROM merchants"
            
            with self.data_loader.get_engine().connect() as conn:
                merchant_ids = [row[0] for row in conn.execute(query).fetchall()]
            
            processed_count = 0
            for i in range(0, len(merchant_ids), batch_size):
                batch = merchant_ids[i:i + batch_size]
                
                for merchant_id in batch:
                    try:
                        self.calculate_merchant_score(merchant_id)
                        processed_count += 1
                    except Exception as e:
                        logger.error(f"更新商家 {merchant_id} 评分时发生错误: {e}")
                        continue
            
            return processed_count
            
        except Exception as e:
            logger.error(f"批量更新商家评分时发生错误: {e}")
            raise
    
    def _scale_score(self, raw_score: float) -> float:
        """将原始评分转换为最终分数.
        
        Args:
            raw_score: 原始评分(0-1)
            
        Returns:
            float: 最终分数(0-1000)
            
        转换步骤:
        1. 对原始分数进行Sigmoid变换
        2. 将结果映射到目标分数范围
        """
        min_score = SCORE_PARAMS["min_score"]
        max_score = SCORE_PARAMS["max_score"]
        
        # Sigmoid变换使分布更平滑
        sigmoid = 1 / (1 + np.exp(-10 * (raw_score - 0.5)))
        
        # 映射到目标范围
        final_score = min_score + sigmoid * (max_score - min_score)
        
        return round(final_score, 2)
    
    def _determine_credit_level(self, score: float) -> str:
        """根据分数确定信用等级.
        
        Args:
            score: 信用评分
            
        Returns:
            str: 信用等级(S+到D)
        """
        for min_score, max_score, level in SCORE_RANGES:
            if min_score <= score <= max_score:
                return level
        return "D"  # 默认最低等级
    
    def _get_merchant_privileges(self, credit_level: str) -> List[str]:
        """获取商家信用等级对应的权益.
        
        Args:
            credit_level: 信用等级
            
        Returns:
            List[str]: 权益列表
        """
        return MERCHANT_PRIVILEGES.get(credit_level, [])
    
    def _save_merchant_score(
        self,
        merchant_id: str,
        score: float,
        dimension_scores: Dict[str, float]
    ) -> bool:
        """保存商家评分记录.
        
        Args:
            merchant_id: 商家ID
            score: 总分
            dimension_scores: 维度得分
            
        Returns:
            bool: 保存是否成功
        """
        return self.data_loader.save_score(
            entity_id=merchant_id,
            entity_type="merchant",
            score=score,
            score_details=dimension_scores
        )